package services

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"vala/tools"
)

type CustomService struct {
	Config           ServiceConfig
	Dir              string
	Process          *os.Process
	ChanProcessState chan *os.ProcessState
	ProcessState     *os.ProcessState
}

func NewCustomService(baseDir string) *CustomService {
	config := ServiceConfig{}
	data, err := ioutil.ReadFile(filepath.Join(baseDir, "service.yaml"))
	if err != nil {
		fmt.Print(err)
	}
	_ = yaml.Unmarshal(data, &config)

	// 替换变量
	config.Cmd = strings.ReplaceAll(config.Cmd, "{baseDir}", baseDir)
	config.PidFile = strings.ReplaceAll(config.PidFile, "{baseDir}", baseDir)
	for i, arg := range config.Args {
		config.Args[i] = strings.ReplaceAll(arg, "{baseDir}", baseDir)
	}

	fmt.Println(config)
	return &CustomService{
		Dir:              baseDir,
		ChanProcessState: make(chan *os.ProcessState),
		Config:           config,
	}
}

func (service *CustomService) Start() {
	var execFile = service.Config.Cmd
	if !filepath.IsAbs(service.Config.Cmd) {
		execFile = filepath.Join(service.Dir, service.Config.Cmd)
	}
	fmt.Println(execFile)
	if !service.Status() {
		service.ProcessState = nil
		service.Process, service.ChanProcessState = tools.StartProcess(
			execFile,
			service.Config.Args,
		)

		// 写入pid文档
		file, error := os.OpenFile(service.Config.PidFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
		if error != nil {
			panic(error)
		}
		file.WriteString(fmt.Sprintf("%d", service.Process.Pid))
		defer file.Close()
	}
}

func (service *CustomService) Stop() {
	if service.Status() {
		service.Process.Kill()
		service.ProcessState = <-service.ChanProcessState
	}
}

func (service *CustomService) Reload() {
	service.Stop()
	service.Start()
}

// 目前仍然以Pid文件是否存在来判断
func (service *CustomService) Status() bool {
	var pidFile = service.Config.PidFile
	if !filepath.IsAbs(service.Config.PidFile) {
		pidFile = filepath.Join(service.Dir, pidFile)
	}
	fmt.Println(pidFile)
	if tools.IsExist(pidFile) {
		pidByt, error := ioutil.ReadFile(pidFile)
		if error != nil {
			return false
		}
		// 获取PID
		pid, error := strconv.Atoi(strings.TrimRight(strings.TrimRight(string(pidByt), "\n"), "\r"))
		if error != nil {
			panic(error)
		}
		_, error = os.FindProcess(pid)
		if error != nil {
			return false
		}
		if service.ProcessState != nil && service.ProcessState.Exited() {
			return false
		}

		return true
	}

	return false
}
